#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using UTable.Input;
using UTable.Input.MultiTouch;

namespace UTable.Objects.Handlers
{
	public class NFingersHandler: MultiTouchEventHandlerClass
	{
		public override void OnMultiTouch(MultiTouchEventArgs args)
		{
			Boolean shouldSendMoveEvent = false;
			Boolean shouldSendStartEvent = false;
			Boolean shouldSendEndEvent = true;

			// Firstly Scanner all finger move events, and update the current finger position
			foreach (FingerEventArgs finger_event in args.FingerEvents)
			{
				if (finger_event.EventType == FingerEventType.FINGER_MOVE_EVENT && CurrentFingerMap.ContainsKey(finger_event.FingerID))
				{
					CurrentFingerMap[finger_event.FingerID].Position = finger_event.Position;
					shouldSendMoveEvent = true;
				}
			}

			// Then scanner all finger up events
			foreach (FingerEventArgs finger_event in args.FingerEvents)
			{
				if ((finger_event.EventType == FingerEventType.FINGER_UP_EVENT 
                    || finger_event.EventType == FingerEventType.FINGER_OUT_EVENT
                    ) 
                    && CurrentFingerMap.ContainsKey(finger_event.FingerID))
				{
					if (shouldSendEndEvent)
					{
						OnFingersUp(CurrentFingers);
						shouldSendEndEvent = false;
					}
					FingerPoint toRemoveFinger = CurrentFingerMap[finger_event.FingerID];
					CurrentFingerMap.Remove(toRemoveFinger.ID);
					CurrentFingers.RemoveAt(toRemoveFinger.Index);
					for (int i = toRemoveFinger.Index; i < CurrentFingers.Count; i++)
					{
						CurrentFingers[i].Index = i;
					}
					shouldSendMoveEvent = false;
					shouldSendStartEvent = true;
				}
			}
			// Fire the N-Finger-End event

			// Then scanner all finger down events
			foreach (FingerEventArgs finger_event in args.FingerEvents)
			{
				if ((finger_event.EventType == FingerEventType.FINGER_DOWN_EVENT ||
                    finger_event.EventType == FingerEventType.FINGER_IN_EVENT)
                    && !CurrentFingerMap.ContainsKey(finger_event.FingerID))
				{
					if (shouldSendEndEvent)
					{
						OnFingersUp(CurrentFingers);
						shouldSendEndEvent = false;
					}
					FingerPoint toInsertFinger = new FingerPoint(finger_event.FingerID, finger_event.Position, this.CurrentFingers.Count);
					CurrentFingers.Add(toInsertFinger);
					CurrentFingerMap.Add(toInsertFinger.ID, toInsertFinger);
					shouldSendMoveEvent = false;
					shouldSendStartEvent = true;
				}
			}
			// fire the N-Finger-Start event
			if (shouldSendStartEvent)
			{
				OnFingersDown(CurrentFingers);
			}

			// Finally fire the N-Finger-Move event (Occurs only when there are no Finger-Start or Finger-End events
			if (shouldSendMoveEvent)
			{
				OnFingersMove(CurrentFingers);
			}
		}

		private List<FingerPoint> LastFingers = new List<FingerPoint>();
		private int MaxFingerNumber { get; set; }
		private List<FingerPoint> CurrentFingers = new List<FingerPoint>();
		private Dictionary<int, FingerPoint> CurrentFingerMap = new Dictionary<int, FingerPoint>();

		private void OnFingersDown(List<FingerPoint> fingers)
		{
			// Process the Fingers Down Event

			OnNFingersDown(fingers);
			if (NFingersDown != null)
				NFingersDown(fingers);
			
			// Update the LastFingers
			LastFingers.Clear();
			for (int i = 0; i < fingers.Count; i++)
			{
				FingerPoint toInsertFinger = new FingerPoint(fingers[i].ID, fingers[i].Position, fingers[i].Index);
				LastFingers.Add(toInsertFinger);
			}
		}

		private void OnFingersUp(List<FingerPoint> fingers)
		{
			// Process the Fingers Up Event
			OnNFingersUp(fingers);
			if (NFingersUp != null)
				NFingersUp(fingers);

			// LastFingers have no use now. It will be updated by the Fingers Down Event
		}

		private void OnFingersMove(List<FingerPoint> fingers)
		{
			// Process the Fingers Move Event

			OnNFingersMove(LastFingers, fingers);
			if (NFingersMove != null)
				NFingersMove(LastFingers, fingers);

			// Update the LastFingers
			for (int i = 0; i < LastFingers.Count; i++)
			{
				LastFingers[i].Position = fingers[i].Position;
			}
		}


		#region Virtual Methods

		protected virtual void OnNFingersDown(List<FingerPoint> fingers)
		{

		}

		protected virtual void OnNFingersUp(List<FingerPoint> fingers)
		{

		}

		protected virtual void OnNFingersMove(List<FingerPoint> oFigners, List<FingerPoint> nFingers)
		{

		}

		#endregion

		#region Events

		public event FingersDownEventHandler NFingersDown;

		public event FingersMoveEventHandler NFingersMove;

		public event FingersUpEventHandler NFingersUp;
		

		#endregion

	}

}
